package com.lapuda.stream;

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.omg.CORBA.PUBLIC_MEMBER;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author shundong.li
 * @date 2022/1/24
 */
public class StreamApi {
    /**
     * description: 获取流
     * @author shundong.li
     * @date 2022/1/24 10:32
     */
    @Test
    public void test() {
        /**
         * 使用Collection下的 stream() 和 parallelStream() 方法
         */
        List<String> list = new ArrayList<String>();
        list.add("lsd");
        list.add("lxr");
        list.add("ljj");
        /**
         * 获取一个顺序流
         */
        Stream<String> stream = list.stream();
        /**
         * 获取一个并行流
         */
        Stream<String> parallelStream = list.parallelStream();
        stream.forEach(System.out::println);
        parallelStream.forEach(System.out::println);

        /**
         * 使用Arrays 中的 stream() 方法，将数组转成流
         */
        Integer[] integers = new Integer[10];
        Stream<Integer> integerStream = Arrays.stream(integers);

        /**
         * 使用Stream中的静态方法：of()、iterate()、generate()
         */
        Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 5);

        Stream<Integer> iterations = Stream.iterate(0, x -> x + 2).limit(8);

        Stream<Double> mathRandoms = Stream.generate(Math::random).limit(10);

        /**
         * 字符串分割成流
          */
        Pattern pattern = Pattern.compile(",");

        Stream<String> stringStream = pattern.splitAsStream("1,3,4,55");
    }
    /**
     * description: 流的中间操作
     * @author shundong.li
     * @date 2022/1/24 10:43
     */
    @Test
    public void test1(){
        /**
         * filter：过滤流中的某些元素
         *         limit(n)：获取n个元素
         *         skip(n)：跳过n元素，配合limit(n)可实现分页
         *         distinct：通过流中元素的 hashCode() 和 equals() 去除重复元素
         */
        Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
        Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
                .distinct() //6 7 9 8 10 12 14
                .skip(2) //9 8 10 12 14
                .limit(2); //9 8
        newStream.forEach(System.out::println);
        /**
         * description:
         *  映射
         *         map：接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
         *         flatMap：接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流。
         * @author shundong.li
         * @date 2022/1/24 10:57
         */
        List<String> list = Arrays.asList("a,b,c", "4,5,6");
        Stream<String> stringStream = list.stream().map(s -> s.replaceAll(",", ""));

        Stream<String> stringStream1 = list.stream().flatMap(s -> {
            String[] split = s.split(",");
            Stream<String> stream1 = Arrays.stream(split);
            return stream1;
        });

        stringStream1.forEach(System.out::println);
    }
    /**
     * description: 排序
     * @author shundong.li
     * @date 2022/1/24 11:01
     */
    @Test
    public void test2(){
        Student lsd = new Student("lsd", 12);
        Student lxr = new Student("lxr", 38);
        Student ljj = new Student("ljj", 20);

        List<Student> students = Arrays.asList(lsd, lxr, ljj);
        students.stream().sorted((student1,student2)->{
            if(student1.getName().equals(student2.getName())){
                return student1.getAge() - student2.getAge();
            }else {
                return student1.getName().compareTo(student2.getName());
            }
        }).forEach(System.out::println);
    }

    /**
     * description: 流的终止操作        匹配、聚合操作
     * @author shundong.li
     * @date 2022/1/24 11:17
     */
    @Test
    public void test3(){
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

//        boolean allMatch = list.stream().allMatch(e -> e > 10); //false
//        boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
//        boolean anyMatch = list.stream().anyMatch(e -> e > 4);  //true
//
//        Integer findFirst = list.stream().findFirst().get(); //1
//        Integer findAny = list.stream().findAny().get(); //1
//
//        long count = list.stream().count(); //5
//        Integer max = list.stream().max(Integer::compareTo).get(); //5
//        Integer min = list.stream().min(Integer::compareTo).get(); //1

        //是否都大于10
        boolean b = list.stream().allMatch(x -> x > 10);
        //是否不存在大于10
        boolean noneMatch = list.stream().noneMatch(x -> x > 10);
        //是否存在大于10
        boolean anyMath = list.stream().anyMatch(x -> x > 10);
        //获取第一个
        Integer integer = list.stream().findFirst().get();
        //统计个数
        long count = list.stream().count();
        //统计最大值
        Integer max = list.stream().max(Integer::compareTo).get();
        //统计最小值
        Integer min = list.stream().min(Integer::compareTo).get();
    }
    /**
     * description:
     * @author shundong.li
     * @date 2022/1/24 13:35
     */
    @Test
    public void test4(){
        //经过测试，当元素个数小于24时，并行时线程数等于元素个数，当大于等于24时，并行时线程数为16
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);

        Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get();
        System.out.println(v);   // 300

        Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);
        System.out.println(v1);  //310

        Integer v2 = list.stream().reduce(0,
                (x1, x2) -> {
                    System.out.println("stream accumulator: x1:" + x1 + "  x2:" + x2);
                    return x1 - x2;
                },
                (x1, x2) -> {
                    System.out.println("stream combiner: x1:" + x1 + "  x2:" + x2);
                    return x1 * x2;
                });
        System.out.println(v2); // -300

        Integer v3 = list.parallelStream().reduce(0,
                (x1, x2) -> {
                    System.out.println("parallelStream accumulator: x1:" + x1 + "  x2:" + x2);
                    return x1 - x2;
                },
                (x1, x2) -> {
                    System.out.println("parallelStream combiner: x1:" + x1 + "  x2:" + x2);
                    return x1 * x2;
                });
        System.out.println(v3); //197474048
    }

    /**
     * collect的用法
     */
    @Test
    public void test5(){
        Student s1 = new Student("aa", 1);
        Student s2 = new Student("bb", 20);
        Student s3 = new Student("cc", 10);

        List<Student> students = Arrays.asList(s1, s2, s3);
        /**
         * 收集为list
         */
        List<Student> collectStudents = students.stream().collect(Collectors.toList());
        
        List<Integer> collectStudentsAge = students.stream()
                .map(Student::getAge)
                .collect(Collectors.toList());
        /**
         * 收集为set
         */
        Set<String> collectAsSet = students.stream().map(Student::getName).collect(Collectors.toSet());

        /**
         * 收集为map
         */
        Map<String, Integer> collectAsMap = students.stream()
                .collect(Collectors.toMap(Student::getName, Student::getAge));

        /**
         *  将结果储存为字符串，并且以 ，分割
         */
        String s = students.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")"));

        /**
         * 统计结果
         */
        Long count = students.stream().collect(Collectors.counting());

        /**
         * 获取大最大的年龄的student
         */

        System.out.println("-------------------------");
        Student oldestStudent = students.stream().sorted((student1, student2) -> {
            return student2.getAge() - student1.getAge(); })
                .limit(1)
                .collect(Collectors.toList())
                .get(0);

        /**
         * 求所有人年龄之和
         */
        Integer sumAge = students.stream().collect(Collectors.summingInt(Student::getAge));

        /**
         * 求平均年龄
         */
        Double avgAge = students.stream().collect(Collectors.averagingDouble(Student::getAge));

        /**
         * 所有的统计数据
         */
        IntSummaryStatistics statistics = students.stream().collect(Collectors.summarizingInt(Student::getAge));
        long count1 = statistics.getCount();
        long sum = statistics.getSum();
        int min = statistics.getMin();
        int max = statistics.getMax();

        /**
         * 分组
         */
        Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getName));

        //多重分组,先根据类型分再根据年龄分
//        Map<Integer, Map<Integer, List<Student>>> typeAgeMap = students.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge)));

        /**
         * 年龄大于10的为一组
         */
        Map<Boolean, List<Student>> groupByAge = students.stream().collect(Collectors.groupingBy(student -> {
            return student.getAge() > 10;
        }));

        List<Student> students1 = groupByAge.get(true);
        List<Student> students2 = groupByAge.get(false);
        System.out.println("---------------");
        System.out.println(students1);
        System.out.println(students2);
    }
}

class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
